package classes;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import containers.Page;

public class PageParser {
	private static final Pattern wordPattern = Pattern.compile("[\\w[-']]+"); //all word characters
	private static final String nonWordChar = new String("[\\W&&[^']]"); //non-word characters
		
	public PageParser() {
		//empty constructor
	}

	public Page parsePage(final Page page) {
        List<String> words = new ArrayList<String>();
        List<String> theLinks = new ArrayList<String>();
		
        // timer variables
        long parseTime = 0;
		long startTime = 0;
        long finishTime = 0;
        int urlCount = 0;
        
        // start the timer
        Date startDate = new Date();
        startTime = startDate.getTime();
        
		Document doc = Jsoup.parse(page.getContents());
		
		Elements links = doc.select("a[href]");

		//build collection of "valid" links
        for (Element link : links) { //build links and add them to the collection of links found in this page
        	String strLink = buildLink(page.getURL(), link.attr("href"));	        	
        	if (strLink != null) { //validation happens in the PageRetriever
        		theLinks.add(strLink);
        		urlCount++;
        	}
        }

        //build collection of words
        //rough tokenization - may need optimizing
        String[] titleText = doc.title().split("\\s");
        for (String word : titleText) {
        	word = word.replaceAll(nonWordChar, "");
        	if (word.length() > 0) {
        		words.add(word);
        	}
        }
        String[] bodyText = doc.body().text().split("\\s");
        for (String word : bodyText) {
        	word = word.replaceAll(nonWordChar, "");
        	if (word.length() > 0) {
        		words.add(word);
        	}
        }	        
       
        page.setWords(words);
        page.setLinkNumber(urlCount);
        page.setURLs(convertStringListToURLList(theLinks));
        
        
        // stop the timer
        Date finishDate = new Date();
        finishTime = finishDate.getTime();
        parseTime += (finishTime - startTime)/1000; //milliseconds to seconds
        
        page.setParseTime(parseTime);
        
        return page;
	}
	
	/**
	 * Checks to see if link is absolute or relative.
	 * Builds link from absolute path concatenated with relative link found in body of page.
	 * If link is absolute, returns link
	 * @param theAbsolutePath	The URL of the page that contains the link
	 * @param theLink			The link found in the page being parsed
	 * @return String			The absolute path to the linked page
	 */
	public String buildLink(final URL theAbsolutePath, final String theLink) {
		String absolutePath = new String(theAbsolutePath.toString());
		String pathToLink = theLink;
		boolean relative = false;
		boolean absPath = true;
		
		try {
			URL linkURL = new URL(theLink);
		} catch (MalformedURLException e) {
			relative = true;
		}
		if (!theAbsolutePath.getPath().isEmpty()) {
			absPath = false; //www.x.com/x/
		}
		
		if (relative == false) { //link is absolute
			pathToLink = theLink;
		} else if (theLink.startsWith("#")) { //anchor to current page
			pathToLink = absolutePath; //to count in statistics
		} else if (absPath == false) { //www.x.com/x.html || www.x.com/x.html/
			if (!absolutePath.endsWith("/")){ //www.x.com/x.html
				if (!theLink.startsWith("/") || !theLink.startsWith(".")) { //www.x.com/x.html & x/
					pathToLink = absolutePath.substring(0, absolutePath.lastIndexOf("/") + 1) + theLink;
				} else { //www.x.com/x.html & /x/
					pathToLink = absolutePath + theLink;
				}				
			} else { //www.x.com/x.html & /1
				pathToLink = absolutePath.substring(0, absolutePath.lastIndexOf("/") + 1) + theLink;
			}
		} else if (absPath == true) { //www.x.com/ or www.x.com
			if (!absolutePath.endsWith("/") && (!theLink.startsWith("/") || !theLink.startsWith("."))) { //www.x.com
				pathToLink = absolutePath + "/" + theLink; //this is for instances where both absolute and relative have no "/" between them				
			} else { //(www.x.com or www.x.com/) &  
				pathToLink = absolutePath + theLink;
			}
		} else { //concatenate absolute and relative
			pathToLink = absolutePath + theLink;
		}
		
		return pathToLink;
	}
	
	private List<URL> convertStringListToURLList(final List<String> strLinks) {
		List<URL> urls = new ArrayList<URL>();
		for (String link : strLinks) {
			URL currURL = null;
			try {
				currURL = new URL(link);
				urls.add(currURL);
			} catch (MalformedURLException e) {}
		}
		
		return urls;
	}
}
